import express from 'express';
import bodyParser from 'body-parser';
import multipart from 'connect-multiparty';
import fse from 'fs-extra';
import path from 'path';
import cors from 'cors';

const multipartMiddleware = multipart();

const app = express();

app.use(cors());
app.use(bodyParser.json());

// 所有上传的文件存放在该目录下
const UPLOADS_DIR = path.resolve("uploads");

/**
 * 上传
 */
app.post("/upload", multipartMiddleware, (req, res) => {
    const {fileHash, chunkHash} = req.body;

    // 如果临时文件夹(用于保存分片)不存在，则创建
    const chunkDir = path.resolve(UPLOADS_DIR, fileHash);
    if (!fse.existsSync(chunkDir)) {
        fse.mkdirSync(chunkDir);
    }

    // 如果临时文件夹里不存在该分片，则将用户上传的分片移到临时文件夹里
    const chunkPath = path.resolve(chunkDir, chunkHash);
    if (!fse.existsSync(chunkPath)) {
        fse.moveSync(req.files.chunk.path, chunkPath);
    }

    res.send({
        success: true,
        msg: "上传成功",
    });
});

/**
 * 合并
 */
app.post("/merge", async (req, res) => {
    const {fileHash, fileName} = req.body;

    // 最终合并的文件路径
    const filePath = path.resolve(UPLOADS_DIR, fileHash + path.extname(fileName));
    // 临时文件夹路径
    const chunkDir = path.resolve(UPLOADS_DIR, fileHash);

    // 读取临时文件夹，获取该文件夹下“所有文件（分片）名称”的数组对象
    const chunkPaths = fse.readdirSync(chunkDir);

    // 读取临时文件夹获得的文件（分片）名称数组可能乱序，需要重新排序
    chunkPaths.sort((a, b) => a.split("-")[1] - b.split("-")[1]);

    // 遍历文件（分片）数组，将分片追加到文件中
    const pool = chunkPaths.map(
        (chunkName) =>
            new Promise((resolve) => {
                const chunkPath = path.resolve(chunkDir, chunkName);
                // 将分片追加到文件中
                fse.appendFileSync(filePath, fse.readFileSync(chunkPath));
                // 删除分片
                fse.unlinkSync(chunkPath);
                resolve();
            })
    );
    await Promise.all(pool);
    // 等待所有分片追加到文件后，删除临时文件夹
    fse.removeSync(chunkDir);

    res.send({
        success: true,
        msg: "合并成功",
    });
});

/**
 * 校验
 */
app.post("/verify", (req, res) => {
    const {fileHash, fileName} = req.body;

    // 判断服务器上是否存在该hash值的文件
    const filePath = path.resolve(UPLOADS_DIR, fileHash + path.extname(fileName));
    const existFile = fse.existsSync(filePath);

    // 获取已经上传到服务器的文件分片
    const chunkDir = path.resolve(UPLOADS_DIR, fileHash);
    const existChunks = [];
    if (fse.existsSync(chunkDir)) {
        existChunks.push(...fse.readdirSync(chunkDir));
    }

    res.send({
        success: true,
        msg: "校验文件",
        data: {
            existFile,
            existChunks,
        },
    });
});

const server = app.listen(3000, () => {
    console.log(`测试`);
});
